package com.coding365.consumer.filter;

import com.alibaba.dubbo.common.extension.Activate;
import com.alibaba.dubbo.rpc.*;
import com.coding365.consumer.util.TimeSchedule;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

@Activate(group = {"consumer"})
@Component
public class TPMonitorFilter implements Filter {


    private static Map<String,List<Long>[]> methodCallTimeMap = new ConcurrentHashMap<>();

    public static Map<String, List<Long>[]> getMethodCallTimeMap() {
        return methodCallTimeMap;
    }

    @Override
    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {

        Long startTime = System.currentTimeMillis();

        Result result = invoker.invoke(invocation);


        //计算调用花费时间
        Long spendTime = System.currentTimeMillis() - startTime;

        try {
            if (result.getException() != null && result.getException() instanceof Exception){
                throw new Exception(result.getException());
            }
        }catch (Exception e){
            e.printStackTrace();
            return result;
        }


        //通过方法名称获取该方法一分钟内的调用时间队列
        List<Long>[] methodCallTimeMapWithName = getMethodCallTimeMapWithName(invocation.getMethodName());

        //判断当前时间是否为新的一秒
        Boolean isNewSecond = TimeSchedule.isCurrentNewSecond();
        //获取当前时间正处于60s中的第几秒钟
        int index = TimeSchedule.getTick() % 60;
        //取出一秒中的调用时长的队列
        List<Long> queueInSecond = methodCallTimeMapWithName[index];

        //如果是新的一秒中，那么把之前的该位置的数字清除，新建一个新的数组
        if (isNewSecond || queueInSecond == null){
            queueInSecond = new ArrayList<>();
            methodCallTimeMapWithName[index] = queueInSecond;
        }

        queueInSecond.add(spendTime);

        return result;
    }


    //初始化方法的调用时间集合
    private List<Long>[] getMethodCallTimeMapWithName(String methodName){
        List<Long>[] callTimeQueue = methodCallTimeMap.get(methodName);
        //将一分钟分成六十份，相当于60s，每一秒都用一个数组来保存方法的调用情况
        if (callTimeQueue == null){
            callTimeQueue = new List[60];
            methodCallTimeMap.put(methodName,callTimeQueue);
        }

        return callTimeQueue;
    }
}
